package me.tonywang.config;

import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Map;

/**
 * @className: WebMvcConfig
 * @description:
 * @author: WANGHUI
 * @createDate: 2018/6/5 18:33
 * @version: 1.0
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {


    /**
     * fix idWork long cannot work in js
     * http://www.codeweblog.com/java%E5%BA%8F%E5%88%97%E5%8C%96json%E6%97%B6long%E5%9E%8B%E6%95%B0%E5%80%BC%E4%B8%8D%E5%87%86%E7%A1%AE/
     *
     * @return
     */
    @Bean
    SimpleModule simpleModule() {
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
        return simpleModule;
    }


    //@see EnableWebMvcConfiguration
    @Bean
    WebMvcRegistrations webMvcRegistrations() {
        return new WebMvcRegistrations() {
            @Override
            public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
                return new RequestMappingHandlerMapping() {
                    // ========
                    @Override
                    protected void handlerMethodsInitialized(Map<RequestMappingInfo, HandlerMethod> handlerMethods) {
                        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
//                            logger.debug("path : " + entry.getKey().getPatternsCondition().getPatterns());
//                            logger.debug("RequestMappingInfo : " + entry.getKey().getName());
//                            logger.debug("HandlerMethod : " + entry.getValue().getMethod());
//                            if(entry.getKey().getName()==null){
//                                throw new IllegalArgumentException(entry.getValue().getMethod() + "RequestMappingInfo name is null ");
//                            }
                        }
                    }

                    //@see  AbstractHandlerMethodMapping.initHandlerMethods---> getMappingForMethod --> createRequestMappingInfo
                    @Nullable
                    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
                        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(handlerType, RequestMapping.class);
//                        if (requestMapping != null)
//                            logger.debug("handlerType path : " + Arrays.asList(requestMapping.name()));
                        return null;
                    }

                    @Nullable
                    protected RequestCondition<?> getCustomMethodCondition(Method method) {
                        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class);
//                        if (requestMapping != null)
//                            logger.debug("method path : " + Arrays.asList(requestMapping.path()));
                        return null;
                    }

                    @Override
                    protected boolean isHandler(Class<?> beanType) {
                        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
                    }
                };
            }
        };
    }


    /**
     * 过滤器
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean corsFilterRegistrationBean() {
        // 对响应头进行CORS授权
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);
        corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
        corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setMaxAge(3600l);

        // 注册CORS过滤器
        UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
        configurationSource.registerCorsConfiguration("/**", corsConfiguration);
        CorsFilter corsFilter = new CorsFilter(configurationSource);
        return new FilterRegistrationBean(corsFilter);
    }

    /**
     * 注册跨域
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }


    @Bean
    MappedInterceptor interceptorTest() {

        HandlerInterceptor interceptor = new HandlerInterceptor() {
            @Override
            public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
                System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            }

            @Override
            public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
                System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            }
        };
        return new MappedInterceptor(new String[]{"/*"}, interceptor);
    }

}
